from rest_framework import serializers

from goods.models import SKU
from users import constants
from .models import User, Address
from django_redis import get_redis_connection
import re
from rest_framework_jwt.settings import api_settings
from celery_tasks.send_email.tasks import send_verify_email


class UserCreateSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    username = serializers.CharField(
        min_length=5,
        max_length=20,
        error_messages={
            'min_length': '用户名为5-20个字符',
            'max_length': '用户名为5-20个字符'
        }
    )
    password = serializers.CharField(
        write_only=True,
        min_length=8,
        max_length=20,
        error_messages={
            'min_length': '密码为8-20个字符',
            'max_length': '密码为8-20个字符'
        }
    )

    password2 = serializers.CharField(write_only=True)
    mobile = serializers.CharField()
    sms_code = serializers.CharField(write_only=True)
    allow = serializers.BooleanField(write_only=True)
    # 添加token属性,jwt，不接受客户端输入
    token = serializers.CharField(read_only=True, label='登陆状态token')

    # # 定义方法进行验证
    def validate_username(self, value):
        count = User.objects.filter(username=value).count()
        if count > 0:
            raise serializers.ValidationError('改用户名已存在')
        return value

    def validate_mobile(self, value):
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机号格式不正确')
        count = User.objects.filter(mobile=value).count()
        if count > 0:
            raise serializers.ValidationError('该手机已经邦定其他账号')
        return value

    def validate_allow(self, value):
        if not value:
            raise serializers.ValidationError('请同意注册协议')
        return value

    def validate(self, attrs):

        password = attrs.get('password')
        password2 = attrs.get('password2')

        if password != password2:
            raise serializers.ValidationError('两次输入的密码不不一致')

        # 链接redis数据库，取出sms_code
        redis_cli = get_redis_connection('sms')
        key = 'sms_' + attrs.get('mobile')
        sms_code_redis = redis_cli.get(key)
        if not sms_code_redis:
            raise serializers.ValidationError('短信验证码过期')
        # 删除redis中的验证码
        redis_cli.delete(key)
        # 解码
        sms_code_redis = sms_code_redis.decode()
        sms_code_request = attrs.get('sms_code')

        if sms_code_redis != sms_code_request:
            raise serializers.ValidationError('验证码不正确')

        return attrs

    def create(self, validated_data):

        user = User()
        user.username = validated_data.get('username')
        user.mobile = validated_data.get('mobile')
        user.set_password(validated_data.get('password'))

        user.save()

        # 状态保持
        # 获取jwt的方法
        jwt_payload_handLer = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handLer = api_settings.JWT_ENCODE_HANDLER

        payload = jwt_payload_handLer(user)
        token = jwt_encode_handLer(payload)
        # 添加到对象属性中
        user.token = token

        return user


class UserDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'mobile', 'email', 'email_active']


class EmailSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'email']
        extra_kwargs = {
            'email': {
                'required': True
            }
        }

    # 默认update方法修改全部属性,保存之后直接发送邮件
    def update(self, instance, validated_data):
        email = validated_data.get('email')
        instance.email = email
        instance.save()

        # 生成邮箱链接
        verify_url = instance.generate_verify_email_url()
        # 发送邮件
        send_verify_email.delay(email, verify_url)

        return instance


class UserAddressSerializer(serializers.ModelSerializer):
    """
    用户地址序列化器
    """
    province = serializers.StringRelatedField(read_only=True)
    city = serializers.StringRelatedField(read_only=True)
    district = serializers.StringRelatedField(read_only=True)
    province_id = serializers.IntegerField(label='省ID', required=True)
    city_id = serializers.IntegerField(label='市ID', required=True)
    district_id = serializers.IntegerField(label='区ID', required=True)

    # province = serializers.PrimaryKeyRelatedField(label='省',queryset=Address.objects.all())
    # city = serializers.PrimaryKeyRelatedField(label='市',queryset=Address.objects.all())
    # district = serializers.PrimaryKeyRelatedField(label='区',queryset=Address.objects.all())

    class Meta:
        model = Address
        exclude = ['user', 'is_deleted', 'create_time', 'update_time']

    def validate_mobile(self, value):
        if not re.match(r'1[3-9]\d{9}', value):
            raise serializers.ValidationError('手机号格式不对')
        return value

    def create(self, validated_data):
        # 底层使用self.get_serializer(data=request.data)的时候会自动带context数据，里面有request,format,view
        validated_data['user'] = self.context['request'].user
        # 只是在数据中添加了个user,其他的创建不变，所有使用super().create
        return super().create(validated_data)


class AddressTitleSerializer(serializers.ModelSerializer):
    """
    地址标题序列化器
    """

    class Meta:
        model = Address
        fields = ['title']


class AddUserBrowsingHistorySerializer(serializers.Serializer):
    sku_id = serializers.IntegerField(label='商品SKU编号', min_value=1)


    def validate_sku_id(self, value):
        # 验证该商品是否存在
        try:
            sku = SKU.objects.get(id=value)
        except SKU.DoesNotExist:
            raise serializers.ValidationError('该商品不存在')

        return value

    def create(self, validated_data):

        # 链接redis数据库存入sku_id
        user_id = self.context['request'].user.id
        sku_id = validated_data.get('sku_id')

        redis_cli = get_redis_connection('history')
        # 创建管道
        p1 = redis_cli.pipeline()

        # 移除以存在的该商品编号
        p1.lrem('history_%d' % user_id, 0, sku_id)
        # 添加新的浏览记录
        p1.lpush('history_%d' % user_id, sku_id)
        # 截取浏览历史记录上线
        p1.ltrim('history_%d' % user_id, 0, constants.USER_BROWSING_HISTORY_COUNTS_LIMIT - 1)

        p1.execute()

        return validated_data
